// copyright 1993 Michael B. Johnson; some portions copyright 1994, MIT
// see COPYRIGHT for reuse legalities
//

#import "RIBScale.h"

@implementation RIBScale

+ initialize { return [RIBScale setVersion:1], self; }

- init
{
  [super init];
  sx = 1.0;
  sy = 1.0;
  sz = 1.0;

  N3D_CopyMatrix(N3DIdentityMatrix, myMatrix);
  myMatrix[0][0] = sx;
  myMatrix[1][1] = sy;
  myMatrix[2][2] = sz;

  return self;
}

- awake
{
  [super awake];
  N3D_CopyMatrix(N3DIdentityMatrix, myMatrix);

  myMatrix[0][0] = sx;
  myMatrix[1][1] = sy;
  myMatrix[2][2] = sz;

  return self;
}

- setSX:(RtFloat)newSX sy:(RtFloat)newSY sz:(RtFloat)newSZ
{
  sx = newSX;
  sy = newSY;
  sz = newSZ;

  // prman totally loses its lunch if you give it a scale of 0
  // but if you give it a value of, say, 0.00001, it's okay
  //NXLogError("setting scale to: %f %f %f", sx, sy, sz);
  if (sx == 0)
  {  sx = 0.00001;
  }
  if (sy == 0)
  {  sy = 0.00001;
  }
  if (sz == 0)
  {  sz = 0.00001;
  }
  //N3D_CopyMatrix(N3DIdentityMatrix, myMatrix);
  myMatrix[0][0] = sx;
  myMatrix[1][1] = sy;
  myMatrix[2][2] = sz;

  //NXLogError("set scale to: %f %f %f", sx, sy, sz);
  return self;
}

- getSX:(RtFloat *)sxPtr sy:(RtFloat *)syPtr sz:(RtFloat *)szPtr
{
  *sxPtr = sx;
  *syPtr = sy;
  *szPtr = sz;

  return self;
}

- (BOOL)isLerpable { return YES; }

// note: because we've made the WWSampleList "safe" for having
// multiple samples with the same data, it's perfectly valid to return
// yourself or b
- lerpWith:b by:(float)uValue
{
   id      newMe = nil;
  RtFloat  sxA, syA, szA;
  RtFloat  sxB, syB, szB;

   if (([self class] != [b class]) || (uValue <= 0.0))
   {  return self;
   }

   if (uValue >= 1.0)
   {  return b;
   }

   newMe = [super lerpWith:b by:uValue]; // this makes a copy for us

   // okay, now do the specific stuff for this class
   [self getSX:&sxA sy:&syA sz:&szA];
   [b getSX:&sxB sy:&syB sz:&szB];
   [newMe setSX:(sxA + ((sxB - sxA) * uValue))
             sy:(syA + ((syB - syA) * uValue))
             sz:(szA + ((szB - szA) * uValue))];

   return newMe;
}

- lerpSelfWith:b by:(float)uValue
{
  RtFloat  sxA, syA, szA;
  RtFloat  sxB, syB, szB;

   if (([self class] != [b class]) || (uValue <= 0.0))
   {  return self;
   }

   if (uValue >= 1.0)
   {  return b;
   }

   [super lerpSelfWith:b by:uValue]; // this makes a copy for us

   // okay, now do the specific stuff for this class
   [self getSX:&sxA sy:&syA sz:&szA];
   [b getSX:&sxB sy:&syB sz:&szB];
   [self setSX:(sxA + ((sxB - sxA) * uValue))
            sy:(syA + ((syB - syA) * uValue))
            sz:(szA + ((szB - szA) * uValue))];

   return self;
}

- (BOOL)isMoot
{
  if ((sx == 1.0) && (sy == 1.0) && (sz == 1.0))  {  return YES; }
  return NO;
}

- (BOOL)theSameAs:otherRIBCommand
{
  RtFloat  theSX, theSY, theSZ;


  [otherRIBCommand getSX:&theSX sy:&theSY sz:&theSZ];
  if (sx != theSX)
  {  return NO;
  }
  if (sy != theSY)
  {  return NO;
  }
  if (sz != theSZ)
  {  return NO;
  }

  return [super theSameAs:otherRIBCommand];
}


- renderSelf:(WW3DCamera *)camera  startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
{
  RiScale(sx, sy, sz);

  return self;
}

- transformCTM:(WW3DAttributeState *)attributeState startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
{ 
  RtMatrix  aMatrix, tmpMatrix;

  [attributeState getTransformMatrix:aMatrix];
  N3DMultiplyMatrix(myMatrix, aMatrix, tmpMatrix);
  [attributeState setTransformMatrix:tmpMatrix];

  //NXLogError("RIBScale myMatrix (-transformCTM:startingAt:endingAt):\n");
  //NXLogError("\t%f %f %f %f\n",  myMatrix[0][0], myMatrix[0][1], myMatrix[0][2], myMatrix[0][3]);
  //NXLogError("\t%f %f %f %f\n",  myMatrix[1][0], myMatrix[1][1], myMatrix[1][2], myMatrix[1][3]);
  //NXLogError("\t%f %f %f %f\n",  myMatrix[2][0], myMatrix[2][1], myMatrix[2][2], myMatrix[2][3]);
  //NXLogError("\t%f %f %f %f\n", myMatrix[3][0], myMatrix[3][1], myMatrix[3][2], myMatrix[3][3]);
  //NXLogError("RIBScale aMatrix (-transformCTM:startingAt:endingAt):\n");
  //NXLogError("\t%f %f %f %f\n",  aMatrix[0][0], aMatrix[0][1], aMatrix[0][2], aMatrix[0][3]);
  //NXLogError("\t%f %f %f %f\n",  aMatrix[1][0], aMatrix[1][1], aMatrix[1][2], aMatrix[1][3]);
  //NXLogError("\t%f %f %f %f\n",  aMatrix[2][0], aMatrix[2][1], aMatrix[2][2], aMatrix[2][3]);
  //NXLogError("\t%f %f %f %f\n", aMatrix[3][0], aMatrix[3][1], aMatrix[3][2], aMatrix[3][3]);

  return self; 
}

- (BOOL)isMotionBlurrable { return YES; }

- writeEve:(NXStream *)stream atTabLevel:(int)tab
{
   int  i;


   for (i = 0; i < tab; i++)
   {  NXPrintf(stream, "\t");
   }
   NXPrintf(stream, "Scale %g %g %g;", sx, sy, sz); 
   return self;
}

- writeInventorAtTime:(float)currentTime to:(NXStream *)stream atTabLevel:(int)tab
{
   int  i;


   for (i = 0; i < tab; i++)
   {  NXPrintf(stream, "\t");
   }
   NXPrintf(stream, "Scale {\n");
   for (i = 0; i < (tab+1); i++)
   {  NXPrintf(stream, "\t");
   }
   NXPrintf(stream, "scaleFactor %g %g %g\n", sx, sy, sz);
   for (i = 0; i < tab; i++)
   {  NXPrintf(stream, "\t");
   }
   NXPrintf(stream, "}");

   return self;

}
#define typeVector "fff"
#define typeValues &sx, &sy, &sz

- read:(NXTypedStream*)stream 
{
    int version;
    [super read:stream];

NX_DURING
    version = NXTypedStreamClassVersion(stream,"RIBScale");
    if (version == 0) NXReadTypes(stream,"i",&version), version=1;
    if (version == 1)
    {  NXReadTypes(stream,typeVector,typeValues);
    } 
NX_HANDLER
   NXLogError("in read: %s, exception [%d] raised.\n", 
                 [[self class] name], NXLocalHandler.code);
   return nil;
NX_ENDHANDLER
    return self;
}

- write:(NXTypedStream*)stream 
{
    [super write:stream];

    NXWriteTypes(stream,typeVector, typeValues);

    return self;
}

@end

